{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "cc93d05f",
      "metadata": {
        "id": "cc93d05f"
      },
      "source": [
        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/03-langchain-conversational-memory.ipynb) [![Open nbviewer](https://raw.githubusercontent.com/pinecone-io/examples/master/assets/nbviewer-shield.svg)](https://nbviewer.org/github/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/03-langchain-conversational-memory.ipynb)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "hcqKO0aI6_PI",
      "metadata": {
        "id": "hcqKO0aI6_PI"
      },
      "source": [
        "#### [LangChain Handbook](https://pinecone.io/learn/langchain)\n",
        "\n",
        "# Conversational Memory\n",
        "\n",
        "Conversational memory is how chatbots can respond to our queries in a chat-like manner. It enables a coherent conversation, and without it, every query would be treated as an entirely independent input without considering past interactions.\n",
        "\n",
        "The memory allows a _\"agent\"_ to remember previous interactions with the user. By default, agents are *stateless* — meaning each incoming query is processed independently of other interactions. The only thing that exists for a stateless agent is the current input, nothing else.\n",
        "\n",
        "There are many applications where remembering previous interactions is very important, such as chatbots. Conversational memory allows us to do that.\n",
        "\n",
        "In this notebook we'll explore this form of memory in the context of the LangChain library.\n",
        "\n",
        "We'll start by importing all of the libraries that we'll be using in this example."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "uZR3iGJJtdDE",
      "metadata": {
        "id": "uZR3iGJJtdDE",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "98873b1a-5688-4f64-c400-e17be707c56b"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m344.0/344.0 KB\u001b[0m \u001b[31m6.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m70.1/70.1 KB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m41.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m73.5/73.5 KB\u001b[0m \u001b[31m785.2 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.8/62.8 KB\u001b[0m \u001b[31m2.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m38.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h"
          ]
        }
      ],
      "source": [
        "!pip install -qU langchain openai tiktoken"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "66fb9c2a",
      "metadata": {
        "id": "66fb9c2a"
      },
      "outputs": [],
      "source": [
        "import inspect\n",
        "\n",
        "from getpass import getpass\n",
        "from langchain import OpenAI\n",
        "from langchain.chains import LLMChain, ConversationChain\n",
        "from langchain.chains.conversation.memory import (ConversationBufferMemory, \n",
        "                                                  ConversationSummaryMemory, \n",
        "                                                  ConversationBufferWindowMemory,\n",
        "                                                  ConversationKGMemory)\n",
        "from langchain.callbacks import get_openai_callback\n",
        "import tiktoken"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "wPdWz1IdxyBR",
      "metadata": {
        "id": "wPdWz1IdxyBR"
      },
      "source": [
        "To run this notebook, we will need to use an OpenAI LLM. Here we will setup the LLM we will use for the whole notebook, just input your openai api key when prompted. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "c02c4fa2",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "c02c4fa2",
        "outputId": "ed941db8-a50d-4e7d-d302-7b6b8c371c25"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "··········\n"
          ]
        }
      ],
      "source": [
        "OPENAI_API_KEY = getpass()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "baaa74b8",
      "metadata": {
        "id": "baaa74b8"
      },
      "outputs": [],
      "source": [
        "llm = OpenAI(\n",
        "    temperature=0, \n",
        "    openai_api_key=OPENAI_API_KEY,\n",
        "    model_name='text-davinci-003'  # can be used with llms like 'gpt-3.5-turbo'\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "309g_2pqxzzB",
      "metadata": {
        "id": "309g_2pqxzzB"
      },
      "source": [
        "Later we will make use of a `count_tokens` utility function. This will allow us to count the number of tokens we are using for each call. We define it as so:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "id": "DsC3szr6yP3L",
      "metadata": {
        "id": "DsC3szr6yP3L"
      },
      "outputs": [],
      "source": [
        "def count_tokens(chain, query):\n",
        "    with get_openai_callback() as cb:\n",
        "        result = chain.run(query)\n",
        "        print(f'Spent a total of {cb.total_tokens} tokens')\n",
        "\n",
        "    return result"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "CnNF6i9r8RY_",
      "metadata": {
        "id": "CnNF6i9r8RY_"
      },
      "source": [
        "Now let's dive into **Conversational Memory**."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6e1f31b4",
      "metadata": {
        "id": "6e1f31b4"
      },
      "source": [
        "## What is memory?"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5b919c3a",
      "metadata": {
        "id": "5b919c3a"
      },
      "source": [
        "**Definition**: Memory is an agent's capacity of remembering previous interactions with the user (think chatbots)\n",
        "\n",
        "The official definition of memory is the following:\n",
        "\n",
        "\n",
        "> By default, Chains and Agents are stateless, meaning that they treat each incoming query independently. In some applications (chatbots being a GREAT example) it is highly important to remember previous interactions, both at a short term but also at a long term level. The concept of “Memory” exists to do exactly that.\n",
        "\n",
        "\n",
        "As we will see, although this sounds really straightforward there are several different ways to implement this memory capability."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3343a0e2",
      "metadata": {
        "id": "3343a0e2"
      },
      "source": [
        "Before we delve into the different memory modules that the library offers, we will introduce the chain we will be using for these examples: the `ConversationChain`."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6c9c13e9",
      "metadata": {
        "id": "6c9c13e9"
      },
      "source": [
        "As always, when understanding a chain it is interesting to peek into its prompt first and then take a look at its `._call` method. As we saw in the chapter on chains, we can check out the prompt by accessing the `template` within the `prompt` attribute."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "96ff1ce3",
      "metadata": {
        "id": "96ff1ce3"
      },
      "outputs": [],
      "source": [
        "conversation = ConversationChain(\n",
        "    llm=llm, \n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "id": "90ad394d",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "90ad394d",
        "outputId": "1c641d37-b3e7-40d5-815b-936fcd2d9a2a"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
            "\n",
            "Current conversation:\n",
            "{history}\n",
            "Human: {input}\n",
            "AI:\n"
          ]
        }
      ],
      "source": [
        "print(conversation.prompt.template)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9f8b1e0c",
      "metadata": {
        "id": "9f8b1e0c"
      },
      "source": [
        "Interesting! So this chain's prompt is telling it to chat with the user and try to give truthful answers. If we look closely, there is a new component in the prompt that we didn't see when we were tinkering with the `LLMMathChain`: _history_. This is where our memory will come into play."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4a7e7770",
      "metadata": {
        "id": "4a7e7770"
      },
      "source": [
        "What is this chain doing with this prompt? Let's take a look."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "43bfd2da",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "43bfd2da",
        "outputId": "489437a5-0f0b-412a-f817-f0df817211c2"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "    def _call(self, inputs: Dict[str, Any]) -> Dict[str, str]:\n",
            "        known_values = self.prep_inputs(inputs.copy())\n",
            "        return self.apply([known_values])[0]\n",
            "     def apply(self, input_list: List[Dict[str, Any]]) -> List[Dict[str, str]]:\n",
            "        \"\"\"Utilize the LLM generate method for speed gains.\"\"\"\n",
            "        response = self.generate(input_list)\n",
            "        return self.create_outputs(response)\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(inspect.getsource(conversation._call), inspect.getsource(conversation.apply))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "84e664af",
      "metadata": {
        "id": "84e664af"
      },
      "source": [
        "Nothing really magical going on here, just a straightforward pass through an LLM. In fact, this chain inherits these methods directly from the `LLMChain` without any modification:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "d8f4aa79",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "d8f4aa79",
        "outputId": "ca3413ec-1ceb-4160-f6e9-2031350780a0"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "    def _call(self, inputs: Dict[str, Any]) -> Dict[str, str]:\n",
            "        known_values = self.prep_inputs(inputs.copy())\n",
            "        return self.apply([known_values])[0]\n",
            "     def apply(self, input_list: List[Dict[str, Any]]) -> List[Dict[str, str]]:\n",
            "        \"\"\"Utilize the LLM generate method for speed gains.\"\"\"\n",
            "        response = self.generate(input_list)\n",
            "        return self.create_outputs(response)\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(inspect.getsource(LLMChain._call), inspect.getsource(LLMChain.apply))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6aaa70bf",
      "metadata": {
        "id": "6aaa70bf"
      },
      "source": [
        "So basically this chain combines an input from the user with the conversation history to generate a meaningful (and hopefully truthful) response."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "19f5172f",
      "metadata": {
        "id": "19f5172f"
      },
      "source": [
        "Now that we've understood the basics of the chain we'll be using, we can get into memory. Let's dive in!"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0f1a33f6",
      "metadata": {
        "id": "0f1a33f6"
      },
      "source": [
        "## Memory types"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4d732b7a",
      "metadata": {
        "id": "4d732b7a"
      },
      "source": [
        "In this section we will review several memory types and analyze the pros and cons of each one, so you can choose the best one for your use case."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "04d70642",
      "metadata": {
        "id": "04d70642"
      },
      "source": [
        "### Memory type #1: ConversationBufferMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "53d3cb2b",
      "metadata": {
        "id": "53d3cb2b"
      },
      "source": [
        "The `ConversationBufferMemory` does just what its name suggests: it keeps a buffer of the previous conversation excerpts as part of the context in the prompt."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d80a974a",
      "metadata": {
        "id": "d80a974a"
      },
      "source": [
        "**Key feature:** _the conversation buffer memory keeps the previous pieces of conversation completely unmodified, in their raw form._"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "id": "2267f1f0",
      "metadata": {
        "id": "2267f1f0"
      },
      "outputs": [],
      "source": [
        "conversation_buf = ConversationChain(\n",
        "    llm=llm,\n",
        "    memory=ConversationBufferMemory()\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "lseziAMcAyvX",
      "metadata": {
        "id": "lseziAMcAyvX"
      },
      "source": [
        "We pass a user prompt the the `ConversationBufferMemory` like so:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "id": "M0cwooC5A5Id",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "M0cwooC5A5Id",
        "outputId": "8a8178eb-b9ac-45cf-baed-255b413b0630"
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'input': 'Good morning AI!',\n",
              " 'history': '',\n",
              " 'response': \" Good morning! It's a beautiful day today, isn't it? How can I help you?\"}"
            ]
          },
          "metadata": {},
          "execution_count": 32
        }
      ],
      "source": [
        "conversation_buf(\"Good morning AI!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "xlKINTFYA9eo",
      "metadata": {
        "id": "xlKINTFYA9eo"
      },
      "source": [
        "This one call used a total of `85` tokens, but we can't see that from the above. If we'd like to count the number of tokens being used we just pass our conversation chain object and the message we'd like to input via the `count_tokens` function we defined earlier:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "id": "d1bd5a88",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "d1bd5a88",
        "outputId": "cb593afd-7efd-4c0e-cf04-82dc1a324aff"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 179 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Interesting! Large Language Models are a type of artificial intelligence that can process natural language and generate text. They can be used to generate text from a given context, or to answer questions about a given context. Integrating them with external knowledge can help them to better understand the context and generate more accurate results. Is there anything else I can help you with?'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 33
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_buf, \n",
        "    \"My interest here is to explore the potential of integrating Large Language Models with external knowledge\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "id": "146170ca",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "146170ca",
        "outputId": "dbb6f78c-b169-463e-c1c8-a35151894f56"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 268 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Well, integrating Large Language Models with external knowledge can open up a lot of possibilities. For example, you could use them to generate more accurate and detailed summaries of text, or to answer questions about a given context more accurately. You could also use them to generate more accurate translations, or to generate more accurate predictions about future events.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 34
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_buf,\n",
        "    \"I just want to analyze the different possibilities. What can you think of?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "id": "3e15411a",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "3e15411a",
        "outputId": "f6857844-ee6f-49ef-df50-54335f248bd3"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 360 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "'  There are a variety of data sources that could be used to give context to a Large Language Model. These include structured data sources such as databases, unstructured data sources such as text documents, and even audio and video data sources. Additionally, you could use external knowledge sources such as Wikipedia or other online encyclopedias to provide additional context.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 35
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_buf, \n",
        "    \"Which data source types could be used to give context to the model?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "id": "3352cc48",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "3352cc48",
        "outputId": "62294954-cc7e-4ef3-e5fc-19a5c4ffc4c1"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 388 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Your aim is to explore the potential of integrating Large Language Models with external knowledge.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 36
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_buf, \n",
        "    \"What is my aim again?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "431b74ff",
      "metadata": {
        "id": "431b74ff"
      },
      "source": [
        "Our LLM with `ConversationBufferMemory` can clearly remember earlier interactions in the conversation. Let's take a closer look to how the LLM is saving our previous conversation. We can do this by accessing the `.buffer` attribute for the `.memory` in our chain."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "id": "984afd09",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "984afd09",
        "outputId": "4233d17f-1001-48e5-d256-0595e00dbf40"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "Human: Good morning AI!\n",
            "AI:  Good morning! It's a beautiful day today, isn't it? How can I help you?\n",
            "Human: My interest here is to explore the potential of integrating Large Language Models with external knowledge\n",
            "AI:  Interesting! Large Language Models are a type of artificial intelligence that can process natural language and generate text. They can be used to generate text from a given context, or to answer questions about a given context. Integrating them with external knowledge can help them to better understand the context and generate more accurate results. Is there anything else I can help you with?\n",
            "Human: I just want to analyze the different possibilities. What can you think of?\n",
            "AI:  Well, integrating Large Language Models with external knowledge can open up a lot of possibilities. For example, you could use them to generate more accurate and detailed summaries of text, or to answer questions about a given context more accurately. You could also use them to generate more accurate translations, or to generate more accurate predictions about future events.\n",
            "Human: Which data source types could be used to give context to the model?\n",
            "AI:   There are a variety of data sources that could be used to give context to a Large Language Model. These include structured data sources such as databases, unstructured data sources such as text documents, and even audio and video data sources. Additionally, you could use external knowledge sources such as Wikipedia or other online encyclopedias to provide additional context.\n",
            "Human: What is my aim again?\n",
            "AI:  Your aim is to explore the potential of integrating Large Language Models with external knowledge.\n"
          ]
        }
      ],
      "source": [
        "print(conversation_buf.memory.buffer)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4570267d",
      "metadata": {
        "id": "4570267d"
      },
      "source": [
        "Nice! So every piece of our conversation has been explicitly recorded and sent to the LLM in the prompt."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "acf1a90b",
      "metadata": {
        "id": "acf1a90b"
      },
      "source": [
        "### Memory type #2: ConversationSummaryMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01f61fe9",
      "metadata": {
        "id": "01f61fe9"
      },
      "source": [
        "The problem with the `ConversationBufferMemory` is that as the conversation progresses, the token count of our context history adds up. This is problematic because we might max out our LLM with a prompt that is too large to be processed."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0516c7d4",
      "metadata": {
        "id": "0516c7d4"
      },
      "source": [
        "Enter `ConversationSummaryMemory`.\n",
        "\n",
        "Again, we can infer from the name what is going on.. we will keep a summary of our previous conversation snippets as our history. How will we summarize these? LLM to the rescue."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "86b0a905",
      "metadata": {
        "id": "86b0a905"
      },
      "source": [
        "**Key feature:** _the conversation summary memory keeps the previous pieces of conversation in a summarized form, where the summarization is performed by an LLM._"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0ea6050c",
      "metadata": {
        "id": "0ea6050c"
      },
      "source": [
        "In this case we need to send the llm to our memory constructor to power its summarization ability."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "id": "f33a16a7",
      "metadata": {
        "id": "f33a16a7"
      },
      "outputs": [],
      "source": [
        "conversation_sum = ConversationChain(\n",
        "    llm=llm, \n",
        "    memory=ConversationSummaryMemory(llm=llm)\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b64c4896",
      "metadata": {
        "id": "b64c4896"
      },
      "source": [
        "When we have an llm, we always have a prompt ;) Let's see what's going on inside our conversation summary memory:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "id": "c476824d",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "c476824d",
        "outputId": "282be20e-9048-4f37-fc89-8a7eb8dfe1a3"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Progressively summarize the lines of conversation provided, adding onto the previous summary returning a new summary.\n",
            "\n",
            "EXAMPLE\n",
            "Current summary:\n",
            "The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good.\n",
            "\n",
            "New lines of conversation:\n",
            "Human: Why do you think artificial intelligence is a force for good?\n",
            "AI: Because artificial intelligence will help humans reach their full potential.\n",
            "\n",
            "New summary:\n",
            "The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential.\n",
            "END OF EXAMPLE\n",
            "\n",
            "Current summary:\n",
            "{summary}\n",
            "\n",
            "New lines of conversation:\n",
            "{new_lines}\n",
            "\n",
            "New summary:\n"
          ]
        }
      ],
      "source": [
        "print(conversation_sum.memory.prompt.template)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "df90cdf3",
      "metadata": {
        "id": "df90cdf3"
      },
      "source": [
        "Cool! So each new interaction is summarized and appended to a running summary as the memory of our chain. Let's see how this works in practice!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 40,
      "id": "34343665",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "34343665",
        "outputId": "ac04f6bc-9dcb-446c-d4b9-8fd2311d605e"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 290 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "\" Good morning! It's a beautiful day today, isn't it? How can I help you?\""
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 40
        }
      ],
      "source": [
        "# without count_tokens we'd call `conversation_sum(\"Good morning AI!\")`\n",
        "# but let's keep track of our tokens:\n",
        "count_tokens(\n",
        "    conversation_sum, \n",
        "    \"Good morning AI!\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 41,
      "id": "b757bba3",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 71
        },
        "id": "b757bba3",
        "outputId": "9de1823a-0dfe-45ff-fadc-26eff6fdce99"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 440 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "\" That sounds like an interesting project! I'm familiar with Large Language Models, but I'm not sure how they could be integrated with external knowledge. Could you tell me more about what you have in mind?\""
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 41
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_sum, \n",
        "    \"My interest here is to explore the potential of integrating Large Language Models with external knowledge\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 42,
      "id": "d0a373e2",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 106
        },
        "id": "d0a373e2",
        "outputId": "d4f561d7-d1c7-45e5-99ba-266130ee67ba"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 664 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' I can think of a few possibilities. One option is to use a large language model to generate a set of candidate answers to a given query, and then use external knowledge to filter out the most relevant answers. Another option is to use the large language model to generate a set of candidate answers, and then use external knowledge to score and rank the answers. Finally, you could use the large language model to generate a set of candidate answers, and then use external knowledge to refine the answers.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 42
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_sum, \n",
        "    \"I just want to analyze the different possibilities. What can you think of?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 43,
      "id": "2e286f0d",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "2e286f0d",
        "outputId": "9558ef92-5f9c-4818-be8b-1e7e6ec19864"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 799 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' There are many different types of data sources that could be used to give context to the model. These could include structured data sources such as databases, unstructured data sources such as text documents, or even external APIs that provide access to external knowledge. Additionally, the model could be trained on a combination of these data sources to provide a more comprehensive understanding of the context.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 43
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_sum, \n",
        "    \"Which data source types could be used to give context to the model?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 44,
      "id": "891180f2",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "891180f2",
        "outputId": "8035333e-d7c0-4a46-d8b8-acb3501d27e1"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 853 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Your aim is to explore the potential of integrating Large Language Models with external knowledge.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 44
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_sum, \n",
        "    \"What is my aim again?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 45,
      "id": "2d768e44",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "2d768e44",
        "outputId": "3bd42ac9-d56b-45f4-99ac-45cd5a656b94"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\n",
            "The human greeted the AI with a good morning, to which the AI responded with a good morning and asked how it could help. The human expressed interest in exploring the potential of integrating Large Language Models with external knowledge, to which the AI responded positively and asked for more information. The human asked the AI to think of different possibilities, and the AI suggested three options: using the large language model to generate a set of candidate answers and then using external knowledge to filter out the most relevant answers, score and rank the answers, or refine the answers. The human then asked which data source types could be used to give context to the model, to which the AI responded that there are many different types of data sources that could be used, such as structured data sources, unstructured data sources, or external APIs. Additionally, the model could be trained on a combination of these data sources to provide a more comprehensive understanding of the context. The human then asked what their aim was again, to which the AI responded that their aim was to explore the potential of integrating Large Language Models with external knowledge.\n"
          ]
        }
      ],
      "source": [
        "print(conversation_sum.memory.buffer)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0dd35c8c",
      "metadata": {
        "id": "0dd35c8c"
      },
      "source": [
        "You might be wondering.. if the aggregate token count is greater in each call here than in the buffer example, why should we use this type of memory? Well, if we check out buffer we will realize that although we are using more tokens in each instance of our conversation, our final history is shorter. This will enable us to have many more interactions before we reach our prompt's max length, making our chatbot more robust to longer conversations.\n",
        "\n",
        "We can count the number of tokens being used (without making a call to OpenAI) using the `tiktoken` tokenizer like so:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 46,
      "id": "nzijj4RZFX3I",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "nzijj4RZFX3I",
        "outputId": "dc272cbb-acfd-4b4a-f854-8fa63f9732d6"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Buffer memory conversation length: 334\n",
            "Summary memory conversation length: 219\n"
          ]
        }
      ],
      "source": [
        "# initialize tokenizer\n",
        "tokenizer = tiktoken.encoding_for_model('text-davinci-003')\n",
        "\n",
        "# show number of tokens for the memory used by each memory type\n",
        "print(\n",
        "    f'Buffer memory conversation length: {len(tokenizer.encode(conversation_buf.memory.buffer))}\\n'\n",
        "    f'Summary memory conversation length: {len(tokenizer.encode(conversation_sum.memory.buffer))}'\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2bab0c09",
      "metadata": {
        "id": "2bab0c09"
      },
      "source": [
        "_Practical Note: the `text-davinci-003` and `gpt-3.5-turbo` models [have](https://platform.openai.com/docs/api-reference/completions/create#completions/create-max_tokens) a large max tokens count of 4096 tokens between prompt and answer._"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "494830ea",
      "metadata": {
        "id": "494830ea"
      },
      "source": [
        "### Memory type #3: ConversationBufferWindowMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "00762844",
      "metadata": {
        "id": "00762844"
      },
      "source": [
        "Another great option for these cases is the `ConversationBufferWindowMemory` where we will be keeping a few of the last interactions in our memory but we will intentionally drop the oldest ones - short-term memory if you'd like. Here the aggregate token count **and** the per-call token count will drop noticeably. We will control this window with the `k` parameter."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "206a5915",
      "metadata": {
        "id": "206a5915"
      },
      "source": [
        "**Key feature:** _the conversation buffer window memory keeps the latest pieces of the conversation in raw form_"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 60,
      "id": "45be373a",
      "metadata": {
        "id": "45be373a"
      },
      "outputs": [],
      "source": [
        "conversation_bufw = ConversationChain(\n",
        "    llm=llm, \n",
        "    memory=ConversationBufferWindowMemory(k=1)\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 61,
      "id": "fc4dd8a0",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "fc4dd8a0",
        "outputId": "c4ec1cc8-f218-4f7b-e27e-f5fb73e59228"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 85 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "\" Good morning! It's a beautiful day today, isn't it? How can I help you?\""
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 61
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_bufw, \n",
        "    \"Good morning AI!\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 62,
      "id": "b9992e8d",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "b9992e8d",
        "outputId": "ac7ae1af-2329-4766-ac5e-8fce24a1d272"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 178 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Interesting! Large Language Models are a type of artificial intelligence that can process natural language and generate text. They can be used to generate text from a given context, or to answer questions about a given context. Integrating them with external knowledge can help them to better understand the context and generate more accurate results. Do you have any specific questions about this integration?'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 62
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_bufw, \n",
        "    \"My interest here is to explore the potential of integrating Large Language Models with external knowledge\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 63,
      "id": "3f2e98d9",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 89
        },
        "id": "3f2e98d9",
        "outputId": "dc60726a-4be2-480f-892b-443da9b2859e"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 233 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' There are many possibilities for integrating Large Language Models with external knowledge. For example, you could use external knowledge to provide additional context to the model, or to provide additional training data. You could also use external knowledge to help the model better understand the context of a given text, or to help it generate more accurate results.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 63
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_bufw, \n",
        "    \"I just want to analyze the different possibilities. What can you think of?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 64,
      "id": "a2a8d062",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 106
        },
        "id": "a2a8d062",
        "outputId": "dbb27cf0-2e87-41d0-a733-68921d250481"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 245 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Data sources that could be used to give context to the model include text corpora, structured databases, and ontologies. Text corpora provide a large amount of text data that can be used to train the model and provide additional context. Structured databases provide structured data that can be used to provide additional context to the model. Ontologies provide a structured representation of knowledge that can be used to provide additional context to the model.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 64
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_bufw, \n",
        "    \"Which data source types could be used to give context to the model?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 65,
      "id": "ff199a3f",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "ff199a3f",
        "outputId": "81573cf0-7f39-4a8c-8ccd-e79cd80f2523"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 186 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "' Your aim is to use data sources to give context to the model.'"
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 65
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_bufw, \n",
        "    \"What is my aim again?\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f5f59f77",
      "metadata": {
        "id": "f5f59f77"
      },
      "source": [
        "As we can see, it effectively 'fogot' what we talked about in the first interaction. Let's see what it 'remembers'. Given that we set k to be `1`, we would expect it remembers only the last interaction."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6b354c8d",
      "metadata": {
        "id": "6b354c8d"
      },
      "source": [
        "We need to access a special method here since, in this memory type, the buffer is first passed through this method to be sent later to the llm."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 66,
      "id": "85266406",
      "metadata": {
        "id": "85266406"
      },
      "outputs": [],
      "source": [
        "bufw_history = conversation_bufw.memory.load_memory_variables(\n",
        "    inputs=[]\n",
        ")['history']"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 67,
      "id": "5904ae2a",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5904ae2a",
        "outputId": "bd0aa797-7a43-4af5-a531-209aa6272dd4"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Human: What is my aim again?\n",
            "AI:  Your aim is to use data sources to give context to the model.\n"
          ]
        }
      ],
      "source": [
        "print(bufw_history)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ae8b937d",
      "metadata": {
        "id": "ae8b937d"
      },
      "source": [
        "Makes sense. \n",
        "\n",
        "On the plus side, we are shortening our conversation length when compared to buffer memory _without_ a window:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 68,
      "id": "9fbb50fe",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9fbb50fe",
        "outputId": "c35dca36-a7c7-4d61-da19-c28173fa8319"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Buffer memory conversation length: 334\n",
            "Summary memory conversation length: 219\n",
            "Buffer window memory conversation length: 26\n"
          ]
        }
      ],
      "source": [
        "print(\n",
        "    f'Buffer memory conversation length: {len(tokenizer.encode(conversation_buf.memory.buffer))}\\n'\n",
        "    f'Summary memory conversation length: {len(tokenizer.encode(conversation_sum.memory.buffer))}\\n'\n",
        "    f'Buffer window memory conversation length: {len(tokenizer.encode(bufw_history))}'\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "69842cc1",
      "metadata": {
        "id": "69842cc1"
      },
      "source": [
        "_Practical Note: We are using `k=2` here for illustrative purposes, in most real world applications you would need a higher value for k._"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2aea5fc8",
      "metadata": {
        "id": "2aea5fc8"
      },
      "source": [
        "### More memory types!"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "daeb5162",
      "metadata": {
        "id": "daeb5162"
      },
      "source": [
        "Given that we understand memory already, we will present a few more memory types here and hopefully a brief description will be enough to understand their underlying functionality."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f0365333",
      "metadata": {
        "id": "f0365333"
      },
      "source": [
        "#### ConversationSummaryBufferMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "317f298e",
      "metadata": {
        "id": "317f298e"
      },
      "source": [
        "**Key feature:** _the conversation summary memory keeps a summary of the earliest pieces of conversation while retaining a raw recollection of the latest interactions._"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "57ef5c8b",
      "metadata": {
        "id": "57ef5c8b"
      },
      "source": [
        "#### ConversationKnowledgeGraphMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "40248f03",
      "metadata": {
        "id": "40248f03"
      },
      "source": [
        "This is a super cool memory type that was introduced just [recently](https://twitter.com/LangChainAI/status/1625158388824043522). It is based on the concept of a _knowledge graph_ which recognizes different entities and connects them in pairs with a predicate resulting in (subject, predicate, object) triplets. This enables us to compress a lot of information into highly significant snippets that can be fed into the model as context. If you want to understand this memory type in more depth you can check out [this](https://apex974.com/articles/explore-langchain-support-for-knowledge-graph) blogpost."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "91952cd1",
      "metadata": {
        "id": "91952cd1"
      },
      "source": [
        "**Key feature:** _the conversation knowledge graph memory keeps a knowledge graph of all the entities that have been mentioned in the interactions together with their semantic relationships._"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 69,
      "id": "02241bc3",
      "metadata": {
        "id": "02241bc3"
      },
      "outputs": [],
      "source": [
        "# you may need to install this library\n",
        "# !pip install -qU networkx"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 70,
      "id": "c5f10a89",
      "metadata": {
        "id": "c5f10a89"
      },
      "outputs": [],
      "source": [
        "conversation_kg = ConversationChain(\n",
        "    llm=llm, \n",
        "    memory=ConversationKGMemory(llm=llm)\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 71,
      "id": "65957fe2",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 53
        },
        "id": "65957fe2",
        "outputId": "c9561a4a-412a-4d92-865d-9e81a09bb101"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Spent a total of 1565 tokens\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "\" Hi Human! My name is AI. It's nice to meet you. I like mangoes too! Did you know that mangoes are a great source of vitamins A and C?\""
            ],
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            }
          },
          "metadata": {},
          "execution_count": 71
        }
      ],
      "source": [
        "count_tokens(\n",
        "    conversation_kg, \n",
        "    \"My name is human and I like mangoes!\"\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "74054534",
      "metadata": {
        "id": "74054534"
      },
      "source": [
        "The memory keeps a knowledge graph of everything it learned so far."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 72,
      "id": "5a8c54fb",
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5a8c54fb",
        "outputId": "adf96679-087b-4b77-c00d-9bf9e98f9278"
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "[('human', 'human', 'name'), ('human', 'mangoes', 'likes')]"
            ]
          },
          "metadata": {},
          "execution_count": 72
        }
      ],
      "source": [
        "conversation_kg.memory.kg.get_triples()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e1a1ca15",
      "metadata": {
        "id": "e1a1ca15"
      },
      "source": [
        "#### ConversationEntityMemory"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "41e9aeaf",
      "metadata": {
        "id": "41e9aeaf"
      },
      "source": [
        "**Key feature:** _the conversation entity memory keeps a recollection of the main entities that have been mentioned, together with their specific attributes._"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2900a385",
      "metadata": {
        "id": "2900a385"
      },
      "source": [
        "The way this works is quite similar to the `ConversationKnowledgeGraphMemory`, you can refer to the [docs](https://python.langchain.com/en/latest/modules/memory/types/entity_summary_memory.html) if you want to see it in action. "
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d45112bd",
      "metadata": {
        "id": "d45112bd"
      },
      "source": [
        "## What else can we do with memory?"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "78296bff",
      "metadata": {
        "id": "78296bff"
      },
      "source": [
        "There are several cool things we can do with memory in langchain. We can:\n",
        "* implement our own custom memory module\n",
        "* use multiple memory modules in the same chain\n",
        "* combine agents with memory and other tools\n",
        "\n",
        "If this piques your interest, we suggest you to go take a look at the memory [how-to](https://langchain.readthedocs.io/en/latest/modules/memory/how_to_guides.html) section in the docs!"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.11.2"
    },
    "vscode": {
      "interpreter": {
        "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e"
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
